package com.xiashitech.apiservice.service.impl;

import com.xiashitech.apiservice.dao.AgentSystemStatusMapper;
import com.xiashitech.apiservice.dao.model.AgentSystemStatus;
import com.xiashitech.apiservice.service.IDiagnosisService;
import com.xiashitech.interfaces.agent.dto.diagnosis.CommandResp;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;

@Service
@RequiredArgsConstructor(onConstructor =@_(@Autowired))
public class DiagnosisServiceImpl implements IDiagnosisService {

    private final AgentSystemStatusMapper agentSystemStatusMapper;

    /**
     * 存储发送给agent的诊断命令的队列
     */
    private static final Map<String,ConcurrentLinkedQueue<CommandResp>> diagnosisCommands = new HashMap();

    /**
     * 存储agent返回的诊断结果
     */
    private static final Map<String,ConcurrentLinkedQueue<CommandResp>> diagnosisResults = new HashMap();

    /**
     * 缓存上一次agent的状态
     */
    private static final Map<String,Integer> agentStatusMapCache = new HashMap();

    /**
     * 开启
     */
    private static final Integer ON = new Integer(1);

    /**
     * 关闭
     */
    private static final Integer OFF = new Integer(0);

    /**
     * 在线诊断状态：3
     */
    private static final Integer DIAGNOSIS_STATUS = new Integer(3);

    /**
     * agent状态，运行中：1
     */
    private static final Integer RUNNING_STATUS = new Integer(1);

    /**
     * agent获取诊断命令
     * @param systemId
     * @return
     */
    @Override
    public CommandResp getAndRemoveDiagnosisCommand(String systemId, String microServiceId) {
        String diagnosisKey = systemId+microServiceId;
        if(diagnosisCommands.containsKey(diagnosisKey)) {
            ConcurrentLinkedQueue<CommandResp> commandRespQueue = diagnosisCommands.get(diagnosisKey);
            CommandResp commandResp = commandRespQueue.poll();
            return commandResp;
        } else {
            return CommandResp.builder().build();
        }
    }

    /**
     * agent将诊断结果放在服务端缓存
     * @param systemId
     * @param line
     * @param sessionId
     * @param diagnosisResult
     */
    @Override
    public void addCommandResult(String systemId, String microServiceId, String line, Integer sessionId, String diagnosisResult) {
        String diagnosisKey = systemId+microServiceId;
        if(diagnosisResults.containsKey(diagnosisKey)) {
            ConcurrentLinkedQueue<CommandResp> commandRespsQueue = diagnosisResults.get(diagnosisKey);
            if(commandRespsQueue.size() >= 10) {//不严格控制多线程并发，因为多些或者少些结果，对使用不影响,防止内存过快暴涨做了简单控制。
                commandRespsQueue.poll();
            }
            commandRespsQueue.offer(CommandResp.builder().systemId(systemId).microServiceId(microServiceId).line(line).sessionId(sessionId).diagnosisResult(diagnosisResult).build());
        } else {
            diagnosisResults.put(diagnosisKey,new ConcurrentLinkedQueue<CommandResp>(Arrays.asList(CommandResp.builder().systemId(systemId).microServiceId(microServiceId).line(line).sessionId(sessionId).diagnosisResult(diagnosisResult).build())));
        }
    }

    /**
     * 从网页将诊断命令传给agent
     * @param systemId
     * @param line
     * @param sessionId
     */
    @Override
    public void addDiagnosisCommand(String systemId, String microServiceId, String line, Integer sessionId) throws Exception {
        List<AgentSystemStatus> agentSystemStatuses = agentSystemStatusMapper.selectAgentStatus(AgentSystemStatus.builder().systemId(systemId).microServiceId(microServiceId).build());
        if(agentSystemStatuses.size() > 0) {
            Integer agentStatus = agentSystemStatuses.get(0).getAgentStatus();
            if(!agentStatus.equals(DIAGNOSIS_STATUS)) {
                throw new Exception("The command can be sent only under diagnosis status(3) !");
            }
        }
        String diagnosisKey = systemId+microServiceId;
        if(diagnosisCommands.containsKey(diagnosisKey)) {
            ConcurrentLinkedQueue<CommandResp> commandRespQueue = diagnosisCommands.get(diagnosisKey);
            commandRespQueue.offer(CommandResp.builder().systemId(systemId).microServiceId(microServiceId).line(line).sessionId(sessionId).build());
        } else {
            diagnosisCommands.put(diagnosisKey,new ConcurrentLinkedQueue<CommandResp>(Arrays.asList(CommandResp.builder().systemId(systemId).microServiceId(microServiceId).line(line).sessionId(sessionId).build())));
        }
    }

    /**
     * agent将诊断命令传输到网页
     * @param systemId
     * @return
     */
    @Override
    public List<CommandResp> getCommandResults(String systemId, String microServiceId) {
        String diagnosisKey = systemId+microServiceId;
        List<CommandResp> commandResps = new ArrayList();
        if(diagnosisResults.containsKey(diagnosisKey)) {
            ConcurrentLinkedQueue<CommandResp> commandRespsQueue = diagnosisResults.get(diagnosisKey);
            commandRespsQueue.forEach(commandResp -> commandResps.add(commandResp));
            commandRespsQueue.removeAll(commandResps);
            return commandResps;
        } else {
            return commandResps;
        }
    }

    /**
     * 开启/关闭在线诊断
     * @param systemId
     * @param microServiceId
     * @param onoff
     */
    @Override
    public void switchDiagnosis(String systemId, String microServiceId, Integer onoff) throws Exception {
        String diagnosisKey = systemId+microServiceId;
        List<AgentSystemStatus> agentSystemStatuses = agentSystemStatusMapper.selectAgentStatus(AgentSystemStatus.builder().systemId(systemId).microServiceId(microServiceId).build());
        if(agentSystemStatuses.size() > 0) {
            Integer agentStatus = agentSystemStatuses.get(0).getAgentStatus();
            if(ON.equals(onoff)) {
                if(agentStatus.equals(DIAGNOSIS_STATUS)) {
                    return;
                }
                agentStatusMapCache.put(diagnosisKey,agentStatus);
                agentSystemStatusMapper.updateAgentStatus(AgentSystemStatus.builder().systemId(systemId).microServiceId(microServiceId).agentStatus(DIAGNOSIS_STATUS).updateTime(new Date()).build());
            } else if (OFF.equals(onoff)) {
                Integer agentStatusCache = agentStatusMapCache.get(diagnosisKey);
                if(!agentStatus.equals(DIAGNOSIS_STATUS)) {
                    return;
                }
                if(agentStatusCache == null) {
                    agentSystemStatusMapper.updateAgentStatus(AgentSystemStatus.builder().systemId(systemId).microServiceId(microServiceId).agentStatus(RUNNING_STATUS).updateTime(new Date()).build());
                } else {
                    agentSystemStatusMapper.updateAgentStatus(AgentSystemStatus.builder().systemId(systemId).microServiceId(microServiceId).agentStatus(agentStatusCache).updateTime(new Date()).build());
                }
            }
        } else {
            throw new Exception("This service is not found in the system!");
        }
    }
}
